相机标定:确定空间物体的三维坐标 您所在的位置:网站首页 三维 定位 相机标定:确定空间物体的三维坐标

相机标定:确定空间物体的三维坐标

2023-08-26 03:21| 来源: 网络整理| 查看: 265

文章目录 相机标定是什么为什么要相机标定相机标定方法实验过程准备标定图片对每一张图片提取角点信息相机标定去畸变反误差投影源码 总结

相机标定是什么

在图像测量过程以及机器视觉应用中,为确定空间物体表面某点的三维几何位置与其在图像中对应点之间的相互关系,必须建立相机成像的几何模型,这些几何模型参数就是相机参数。在大多数条件下这些参数必须通过实验与计算才能得到,这个求解参数的过程就称之为相机标定(或摄像机标定)。

为什么要相机标定

进行相机标定的目的:求出相机的内、外参数,以及畸变参数。

无论是在图像测量或者机器视觉应用中,相机参数的标定都是非常关键的环节,其标定结果的精度及算法的稳定性直接影响相机工作产生结果的准确性。因此,做好相机标定是做好后续工作的前提,提高标定精度是科研工作的重点所在。

相机标定方法

相机的标定主要有两种: 传统的摄像头标定方法和摄像头自标定方法, 典型 的有:(1)Tsai(传统的标定方法);(2)张正友(介于传统和自标定之间) 。1999 年,微软研究院的张正友提出了基于移动平面模板的相机标定方法。 此方法是介 于传统标定方法和自标定方法之间的一种方法, 传统标定方法虽然精度高设备有 较高的要求, 其操作过程也比较繁琐, 自标定方法的精度不高, 张正友标定算法 克服了这两者的缺点同时又兼备二者的优点, 因此对办公、 家庭的场合使用的桌 面视觉系统 (DVS)很适合。张正友标定方法由于简单、效果好而得到广泛使用。

张正友标定方法的主要思想是:

利用一个棋盘格标定板,在得到一张标定板的图像之后,可以利用相应的图像检测算法得到每一个角点的像素坐标(u,v)。张正友标定法将世界坐标系固定于棋盘格上,则棋盘格上任一点的物理坐标 W=0,由于标定板的世界坐标系是人为事先定义好的,标定板上每一个格子的大小是已知的,我们可以计算得到每一个角点在世界坐标系下的物理坐标(U,V,W=0)。我们将利用这些信息:每一个角点的像素坐标(u,v)、每一个角点在世界坐标系下的物理坐标(U,V,W=0),来进行相机的标定,获得相机的内外参矩阵、畸变参数。

详见:相机标定之张正友标定法数学原理详解

坐标关系图如下: 在这里插入图片描述

世界坐标系 世界坐标系(world coordinate)(xw,yw,zw),也称为测量坐标系,是一个三维直角坐标系,以其为基准可以描述相机和待测物体的空间位置。世界坐标系的位置可以根据实际情况自由确定。世界坐标系的最小单位为mm。

图像坐标系 图像坐标系(image coordinate)(x,y),是像平面上的二维直角坐标系。图像坐标系的原点为镜头光轴与像平面的交点(也称主点,principal point),它的x轴与相机坐标系的xc轴平行,它的y轴与相机坐标系的yc轴平行。图像坐标系的最小单位为mm。

相机坐标系 相机坐标系(camera coordinate)(xc,yc,zc),也是一个三维直角坐标系,原点位于镜头光心处,xc、yc轴分别与像面的两边平行,zc轴为镜头光轴,与像平面垂直。相机坐标系的最小单位为mm。

张正友标定法的标定步骤: 1、打印一张模板并贴在一个平面上; 2、从不同角度拍摄若干张模板图像; 3、检测出图像中的特征点; 4、求出摄像机的外参数(单应性矩阵)和内参数(最大似然估计) ; 5、求出畸变系数; 6、优化求精

实验过程 准备标定图片

标定图片需要使用标定板在不同位置、不同角度、不同姿态下拍摄。标定板需要是黑白相间的矩形构成的棋盘图。 本实验准备的图像为7×5的黑白格棋盘图,6×4个内点 在这里插入图片描述

对每一张图片提取角点信息

使用findChessboardCorners函数提取角点,这里的角点专指的是标定板上的内角点,这些角点与标定板的边缘不接触。FindChessboardCorners是opencv的一个函数,可以用来寻找棋盘图的内角点位置。该函数的功能是判断图像内是否包含完整的棋盘图,如果能够检测完全,就把他们的角点坐标按顺序(逐行,从左到右)记录下来,并返回非0数,否则返回0。角点检测不完全时,可能画不出图像,或者画出红色角点;正确的图像后面有参考。

提取角点可视化如下: ①m1.jpg 在这里插入图片描述

②m2.jpg 在这里插入图片描述

③m3.jpg 在这里插入图片描述

④m4.jpg 在这里插入图片描述

⑤m5.jpg 在这里插入图片描述

如以上系列对比图所示,均成功检测出6*4=24个角点

结果显示,在棋盘格内部无遮挡无干扰的情况下,拍照角度改变对角点检测结果影响不大

相机标定

由控制台打印输出标定结果、相机的内参数矩阵、畸变系数、旋转矩阵、平移向量: ret、mtx、dist、rvecs、tvecs分别为标定结果、相机的内参数矩阵、畸变系数、旋转矩阵、平移向量

去畸变

我们已经得到了相机内参和畸变系数,在将图像去畸变之前,我们还可以使用cv.getOptimalNewCameraMatrix()优化内参数和畸变系数,通过设定自由自由比例因子alpha。当alpha设为0的时候,将会返回一个剪裁过的将去畸变后不想要的像素去掉的内参数和畸变系数;当alpha设为1的时候,将会返回一个包含额外黑色像素点的内参数和畸变系数,并返回一个ROI用于将其剪裁掉

反误差投影

通过反投影误差,我们可以来评估结果的好坏。越接近0,说明结果越理想。通过之前计算的内参数矩阵、畸变系数、旋转矩阵和平移向量,使用cv2.projectPoints()计算三维点到二维图像的投影,然后计算反投影得到的点与图像上检测到的点的误差,最后计算一个对于所有标定图像的平均误差,这个值就是反投影误差。

通过计算得到反投影误差为: total error = 0.15747956749563666 在这里插入图片描述

源码 import cv2 import numpy as np import glob # 找棋盘格角点 # 阈值 criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) #棋盘格模板规格 w = 6 #内角点个数,内角点是和其他格子连着的点 h = 4 # 世界坐标系中的棋盘格点,例如(0,0,0), (1,0,0), (2,0,0) ....,(8,5,0),去掉Z坐标,记为二维矩阵 objp = np.zeros((w*h,3), np.float32) objp[:,:2] = np.mgrid[0:w,0:h].T.reshape(-1,2) # 储存棋盘格角点的世界坐标和图像坐标对 objpoints = [] # 在世界坐标系中的三维点 imgpoints = [] # 在图像平面的二维点 images = glob.glob('picture/*.jpg') for fname in images: img = cv2.imread(fname) gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) ret, corners = cv2.findChessboardCorners(gray, (w,h),None) if ret == True: cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria) objpoints.append(objp) imgpoints.append(corners) cv2.drawChessboardCorners(img, (w,h), corners, ret) cv2.imshow('findCorners',img) cv2.waitKey(1000) cv2.destroyAllWindows() #标定、去畸变 ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None) # mtx:内参数矩阵 # dist:畸变系数 # rvecs:旋转向量 (外参数) # tvecs :平移向量 (外参数) print (("ret:"),ret) print (("mtx:\n"),mtx) print (("dist:\n"),dist) print (("rvecs:\n"),rvecs) print (("tvecs:\n"),tvecs) # 去畸变 img2 = cv2.imread('picture/m2.jpg') h,w = img2.shape[:2] newcameramtx, roi=cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),0,(w,h)) dst = cv2.undistort(img2, mtx, dist, None, newcameramtx) x,y,w,h = roi dst = dst[y:y+h, x:x+w] cv2.imwrite('calibresult.jpg',dst) # 反投影误差 total_error = 0 for i in range(len(objpoints)): imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist) error = cv2.norm(imgpoints[i],imgpoints2, cv2.NORM_L2)/len(imgpoints2) total_error += error print (("total error: "), total_error/len(objpoints)) 总结

实验结果表明张正友的方法有很好的精度。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

      专题文章
        CopyRight 2018-2019 实验室设备网 版权所有